package com.zzs.judge.config;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.PullImageResultCallback;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Image;
import com.zzs.judge.constants.DockerConsts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * Java 容器初始化管理类，负责 Java 运行环境的拉取、创建、检查和管理
 * 主要功能包括：
 * 1. 检查并拉取 Java 镜像
 * 2. 创建 Java 运行容器
 * 3. 检测已有容器是否存在、是否需要重启
 * @author zzs
 * @date 2025/03/28
 */
@Slf4j
@Component
public class CreateJavaContainer {
    @Autowired
    private DockerClient dockerClient;

    @Autowired
    private HostConfig hostConfig;


    /**
     * 创建容器
     *
     * @param name 容器名
     * @return 容器id
     */
    public String createContainer(String name) {
        pullImage();
        String containerId = checkOldContainer(name);
        if (containerId != null) {
            return containerId;
        }
        try {
            System.out.println("开始创建" + name + "容器");;
            containerId = dockerClient
                    .createContainerCmd(DockerConsts.JAVA_IMAGE)
                    .withName(name)
                    .withHostConfig(hostConfig)
                    // 添加保持容器运行的命令
                    .withCmd("tail", "-f", "/dev/null")
//                    确保可以捕获标准错误
                    .withAttachStderr(true)
//                    确保可以捕获标准输出
                    .withAttachStdout(true)
                    .exec()
                    .getId();
            System.out.println(name + "容器创建成功");
            dockerClient.startContainerCmd(containerId).exec();
            System.out.println(name + "容器启动成功");
        } catch (Exception e) {
            System.out.println(name + "容器创建失败");
            throw new RuntimeException(name + "容器创建失败", e);
        }
        return containerId;
    }

    private void pullImage() {
        System.out.println("检查是否有java镜像");
        if (existsImage()) {
            System.out.println("有java镜像");
            return;
        }
        System.out.println("没有java镜像, 开始拉取");
        try {
            dockerClient.pullImageCmd(DockerConsts.JAVA_IMAGE_NAME)
                    .withTag(DockerConsts.JAVA_IMAGE_VERSION)
                    .exec(new PullImageResultCallback())
//                    等待拉取完成
                    .awaitCompletion();
            System.out.println("镜像拉取成功");
        } catch (InterruptedException e) {
            System.out.println("java镜像拉取失败");
            throw new RuntimeException("java镜像拉取失败", e);
        }
    }

    /**
     * 判断是否存在指定的 Java 镜像。
     * <p>
     * 该方法通过 Docker 客户端列出所有的镜像，并遍历每个镜像的标签列表，检查是否有指定的 Java 镜像存在。
     *
     * @return 如果存在指定的 Java 镜像，则返回 true；否则返回 false。
     */
    private boolean existsImage() {
        // 获取所有镜像的列表
        List<Image> imageList = dockerClient.listImagesCmd().exec();
        // 遍历每个镜像
        for (Image image : imageList) {
            String[] repoTags = image.getRepoTags();
            if (repoTags != null) {
                // 遍历每个镜像的标签列表
                for (String repoTag : repoTags) {
                    // 如果镜像标签匹配指定的 Java 镜像名，则返回 true
                    if (DockerConsts.JAVA_IMAGE.equals(repoTag)) {
                        return true;
                    }
                }
            }
        }
        // 如果没有找到指定的 Java 镜像，返回 false
        return false;
    }

    /**
     * 检查容器是否存在: 如果容器不存在, 返回null。如果容器存在, 就检查它的状态, 如果处于"退出"或"死亡"状态,
     * 删除该容器并返回null;如果容器处于可恢复状态, 重新启动并返回containerId
     *
     * @param name 容器名字
     * @return 容器id
     */
    protected String checkOldContainer(String name) {
        System.out.println("开始检查" + name + "容器是否存在");
        List<Container> containerList = dockerClient.listContainersCmd().withShowAll(true).exec();
        if (containerList == null || containerList.isEmpty()) {
            System.out.println(name + "容器不存在");
            return null;
        }
        for (Container container : containerList) {
            String[] names = container.getNames();
            System.out.println(Arrays.toString(names));
            if (names == null || names.length == 0) {
                continue;
            }
//            第一个名字是容器的主名字(创建容器时指定的名字), 本系统所有java容器默认只有主名字
            if (name.equals(names[0].replaceFirst("/", ""))) {
                return handleContainerState(container, name);
            }
        }
        System.out.println(name + "容器不存在");
        return null;
    }

    private String handleContainerState(Container container, String name) {
        System.out.println(name + "容器存在");
        System.out.println("开始检查" + name + "容器存在");
        String state = container.getState();
        String containerId = container.getId();
        if ("exited".equalsIgnoreCase(state) || "dead".equalsIgnoreCase(state)) {
            System.out.println(name + "容器已经退出或死亡, 准备删除该容器");
            dockerClient.removeContainerCmd(containerId).exec();
            System.out.println("成功删除" + name + "容器");
            return null;
        } else {
            System.out.println(name + "容器仍可使用, 准备重启");
            dockerClient.restartContainerCmd(containerId).exec();
            System.out.println(name + "容器成功重启");
            return containerId;
        }
    }
}
